const config = require('../config.js');
const { AI_API_KEY, AI_BASE_API_URL } = require('./ai/config.js');

const OCR_MODEL = 'qwen-vl-max';
const PURPOSE_MODEL = 'qwen-vl-max';

let aiInstance;
async function init() {
    if (aiInstance) {
        return aiInstance;
    }
    const OpenAI = (await import('openai')).default;
    const openAI = new OpenAI({
        apiKey: AI_API_KEY,
        baseURL: AI_BASE_API_URL,
    });
    aiInstance = openAI;
    return aiInstance;
}

async function createImagesCompletion({ imageFileIdList, prompt, model }) {
    if (!prompt) {
        throw new Error('请输入prompt');
    }
    if (typeof prompt !== 'string') {
        throw new Error('prompt 必须是字符串');
    }
    if (!imageFileIdList || imageFileIdList.length == 0) {
        throw new Error('请输入图片');
    }
    const openAI = await init();
    const imageMessages = imageFileIdList.map(createImageContent);
    const content = [...imageMessages];
    content.push({
        type: 'text',
        text: prompt,
    });
    const option = {
        model: model || 'qwen-vl-max',
        messages: [
            {
                role: 'user',
                content,
            },
        ],
    };
    try {
        return await openAI.chat.completions.create(option);
    } catch (error) {
        return error;
    }
}

function getCurrentDate() {
    const date = new Date();
    const year = date.getFullYear();
    const month = date.getMonth() + 1;
    const day = date.getDate();
    return `${year}-${month}-${day}`;
}

async function documentOcr({ imageFileId, imageFileName }) {
    const prompt = `请帮我把图片的内容识别为纯文本，并以JSON的方式返回：
    {fileName: "${imageFileName}", content: "..."}
    要求：
    > 如果有印章，请识别印章内容，并以【印章：xxxx】格式输出
    > 如果是证件，请识别是什么证件，并把证件内的各个字段都输出
    > 如果是手写的字体，请识别此内容，并以【手写体：xxx】格式输出`;
    return ocr({ imageFileId, prompt });
}

async function idOcr({ imageFileId, imageFileName }) {
    const prompt = `我需要识别图片中的证件内容，并以JSON的方式传给别的SDK，
            如果某项无法识别或无内容，留空即可，不要胡乱填写，
        不得含有不符合JSON格式的文本，不要添加注释，去掉多余的空格和换行符：
        {
            "current_time": "${getCurrentDate()}",
            "chinese_name": "xxx",
            "english_name": "xxx",
            "birth": "YYYY-MM-DD",
            "id": "xxx",
            "age": "xxx",
            “is_adult": boolean,
            "expiration": "YYYY-MM-DD",
            "is_expired": boolean,
            "nation": "xxx",
            "is_foreign": boolean,
            "is_complete": boolean,
            "file_name": "${imageFileName}",
            "id_card_side": "front|back"
        }
        current_time为当前时间（${Date.now().toLocaleString()}），
        id如果是港澳居民来往内地通行证，则使用通行证号码
        is_expired表示该证件是否已经过期
        is_adult表示是否成年人，超过18岁即成年，
        is_foreign表示是否外国人
        is_complete表示识别是否完整，如果有任意字段缺失则标记为false
        file_name表示当前图片的文件名，不需要改变
        id_card_side表示证件的正面(front)、背面(back)或正反面都有（front_and_back）
        说明：
        1. 如果证件是港澳居民来往内地通行证，正面一般含有姓名（含英文），出生日期，性别，有效期限，证件号码（通行证号码）
            背面含有姓名，香港身份证件号码和通行证号码（从“持证人曾持有号码为 ???? XX的通行证...”内容中提取），如果是背面，
            id则填写通行证号码，且返回id_card_side,chinese_name,id则可，其它字段不用返回
        2. 如何判断证件的正反面：如果是港澳居民来往内地通行证，背面没有有效期限、出生日期；如果是中华人民共和国居民身份证，背面没有姓名；
        `;
    return ocr({ imageFileId, prompt });
}

async function ocr({ imageFileId, prompt }) {
    const res = await createImagesCompletion({
        prompt,
        imageFileIdList: [imageFileId],
        model: OCR_MODEL,
    });
    let resContent;
    try {
        resContent = res?.choices[0]?.message?.content;
        if (!resContent) {
            console.log('没有content');
            return res;
        }
        resContent = resContent.match(/{[\s\w\W]*}/gm)[0];
        resContent = resContent.replace(/\n/gm, '');
        const resJson = JSON.parse(resContent);
        return resJson;
    } catch (error) {
        console.log('解释JSON失败: ' + resContent);
        console.log('AI返回：' + JSON.stringify(res));
        return res;
    }
}

function parseAIResponseJson(resContent) {
    let content = resContent;
    let matchContent = content.match(/{[\s\w\W]*}/gm);
    if (!matchContent) {
        throw new Error('没有匹配到content: ' + content);
    }
    content = matchContent[0];
    content = content.replace(/\n/gm, '');
    try {
        content = JSON.parse(content);
    } catch (e) {
        throw new Error('Parse AI response to json error: ' + resContent);
    }
    return content;
}

function getPromptByCensorType(censorType) {
    const prompts = config.prompts;
    const item = prompts.find((item) => item.censorType == censorType);
    return item.prompt;
}

function createImageContent(imageFileId) {
    if (!imageFileId) {
        throw new Error('不能创建空白的内容');
    }
    return {
        type: 'image_url',
        image_url: {
            url: imageFileId,
        },
    };
}

async function analyzeFilePurpose({ imageFileId }) {
    console.log('分析文件作用：' + imageFileId);
    const openAI = await init();
    const content = [];
    content.push(createImageContent(imageFileId));
    content.push({
        type: 'text',
        text: `这是一张从pdf里提取出来的首页的截图，请结合文件名标题，告诉我这张图片最有可能来自以下那个文件:
        1. 演员证件.pdf：里面包含演员的各种身份证件，例如港澳居民往来内地通行证、护照、中华人民共和国居民身份证等
        2. 安全保卫方案.pdf：里面包含活动现场的安全保卫方案，有演出名称、活动时间、活动场所等
        3. 演出场所备案证明.pdf: 里面包含一张演出场所经营单位备案证明
        4. 场地使用证明.pdf：里面包含一张《场地使用证明》
        5. 演出场地确认函.pdf：里面包含一张演出场所经营单位提供场地的确认函
        6. 监护人同意书.pdf：由于未成年表演需要监护人同意，所以需要监护人同意书
        7. 表演节目清单.pdf：里面包含一张表演节目清单
        8. 消防应急预案.pdf：里面包含涉及消防安全和应急疏散的相关字眼
        9. 风险自评报告.pdf：里面包含表演承办方对表演活动的风险自评报告
        10. 无违反《营业性演出管理条例》声明.pdf：里面包含一张无违反《营业性演出管理条例》声明、说明或承诺书
        11. 演出场所的消防批准文件.pdf：里面包含一张消防部门对演出场所的批准文件，如：《公众聚集场所投入使用、营业前消防安全检查合格证》
        12. 演员演出同意函.pdf：里面包含一张演员同意参加某场表演活动的同意函
        13. 突出事件应急预案.pdf：里面包含表演承办方关于表演过程中可能出现的突发事件的应急预案
        14. 未成年人证件.pdf：里面包含一张未成年人的证件，如：出生证、户口本、中华人民共和国居民身份证、护照、常住人口登记卡等等
        除了识别文件名外，还需要把这图片内的文本内容返回给我，最后一定要把结果以json的方式返回，
        如：{"fileName": "风险自评报告.pdf", "content": "...."}
        注意：
        1. 不要省略content的内容，完整地把图片的内容返回给我
        2. JSON格式必须正确，key值必须带有双引号，不要添加注释，去掉多余的空格和换行符，能够被JSON.parse解析
        3. 时间都以yyyy-MM-dd格式返回
        4. 假如无法识别文件名，则fileName为空字符串
        另外：
        1. 如果是未成年人证件，则content内容为：{"name": "xxx", "id": "", "expired": "", "age": xx, "isMinor": boolean}
        2. 如果是监护人同意书，则content内容为：{"name": "xxx", "guardian": "xxx"}
        `,
    });
    const option = {
        model: PURPOSE_MODEL,
        messages: [
            {
                role: 'user',
                content,
            },
        ],
    };
    console.log('创建AI识别文件任务');
    const response = await openAI.chat.completions.create(option);
    const resContent = response.choices[0].message.content;
    return parseAIResponseJson(resContent);
}

async function askAI({ prompt, model }) {
    if (!model) {
        throw new Error('Please provide model name');
    }
    if (!prompt) {
        throw new Error('Please provide prompt');
    }
    const openAI = await init();
    const messages = [];
    messages.push({
        role: 'user',
        content: prompt,
    });
    const option = {
        model,
        messages,
    };
    return await openAI.chat.completions.create(option);
}

module.exports = {
    getPromptByCensorType,
    analyzeFilePurpose,
    idOcr,
    documentOcr,
    askAI,
};
